import datetime
import json
import requests
import time
import random
import os
import hashlib
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import cv2
import execjs
def get_permanent_id():
    t = "DDClick521"
    e = datetime.datetime.now()
    n = str(e.year)
    a = f"{e.month:02d}"
    r = f"{e.day:02d}"
    s = f"{e.hour:02d}"
    i = f"{e.minute:02d}"
    o = f"{e.second:02d}"
    c = f"{e.microsecond // 1000:03d}"

    l = random.randint(100000, 999999)
    u = random.randint(100000, 999999)
    d = n + a + r + s + i + o + c + str(l) + str(u) + t

    def J(text):
        return hashlib.md5(text.encode()).hexdigest()

    def h(p):
        n = int(p[:8], 16)
        a = str(n)[:6]
        if len(a) < 6:
            a += "0" * (6 - len(a))
        return a

    p = J(d)
    p = h(p)
    return n + a + r + s + i + o + c + p + str(l) + str(u)


session=requests.session()
with open("dangdang.js", "r", encoding="utf-8") as f:
    js_code = f.read()


js_com=execjs.compile(js_code)
proxies={
    'http': '127.0.0.1:7890',
    'https': '127.0.0.1:7890',
}
headers = {
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,ar;q=0.7",
    "Cache-Control": "no-cache",
    "Connection": "keep-alive",
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "https://login.dangdang.com",
    "Pragma": "no-cache",
    "Referer": "https://login.dangdang.com/",
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0",
    "sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"',
}
def isShowSlide(permanent_id,requestId, rankey):

    url = "https://login.dangdang.com/api/customer/loginapi/isShowSlide"
    data = {
        "t": str(int(time.time() * 1000)),
        "ct": "pc",
        "permanent_id": permanent_id,
        "requestId": requestId,
        "sign": "wQ2eR5DUS69H5SxpNKSezQOVB93J246NcIF8hQkI7Pqbc99DuBjYzxV8ioAi28RZ",
    }
    sign = js_com.call("generateSignature", data, rankey)
    print("sign==>", sign)
    data["sign"] = sign
    response = session.post(url, headers=headers,data=data,proxies=proxies)
    print(response.status_code)
    print(response.text)


def getSlidingVerifyCode(permanent_id,requestId, rankey):

    url = "https://login.dangdang.com/api/customer/loginapi/getSlidingVerifyCode"
    data = {
        "t": str(int(time.time() * 1000)),
        "ct": "pc",
        "permanent_id": permanent_id,
        "requestId": requestId,
        "situation": "login",
        "sign": "mgmdqoaEc/BjQ4wSpO2lngBuL4GV9ODx8DC1zdNcxTCR+qVBVu8+V2jRpT546AB0",
    }
    sign = js_com.call("generateSignature2", data, rankey)
    print("sign==>",sign)
    data["sign"] = sign
    response = session.post(url, headers=headers,data=data,proxies=proxies)
    print(response.status_code)
    data=response.json()
    ddata=data["data"]
    slideImg=ddata["slideImg"]
    y=ddata["y"]
    bgImg=ddata["bgImg"]
    heightRatio=ddata["heightRatio"]
    encryptKey=ddata["encryptKey"]
    token = ddata["token"]
    return {
        "slideImg":slideImg,
        "y":y,
        "bgImg":bgImg,
        "heightRatio":heightRatio,
        "encryptKey":encryptKey,
        "token":token
    }


def getRankey(permanent_id):

    url = "https://login.dangdang.com/api/customer/loginapi/getRankey"
    data = {
        "t": str(int(time.time() * 1000)),
        # "ct": "pc",
        "permanent_id": permanent_id,
        # "requestId": "2509081541045960f0GWhe_a615",
        # "sign": "B4O/uODu5BLKPWmCrsp+ygG72uh21DStVL8fHcpuNzHJtOpH5yo2K0TqXHJGDzPq",
    }
    sign = js_com.call("gerankeysign", data)
    print("sign==>", sign)
    data["sign"] = sign
    response = requests.post(url, headers=headers,data=data,proxies=proxies)
    data=response.json()
    print("rankeydata==>",data)
    requestId=data["requestId"]
    rankey=data["rankey"]
    return {
        "requestId":requestId,
        "rankey":rankey
    }


def identify_gap(bg: str, tp: str, out: str) -> dict:
    """识别滑块缺口位置"""
    bg_img = cv2.imread(bg)
    tp_img = cv2.imread(tp)

    # 边缘检测
    bg_edge = cv2.Canny(bg_img, 100, 200)
    tp_edge = cv2.Canny(tp_img, 100, 200)

    # 转彩色
    bg_pic = cv2.cvtColor(bg_edge, cv2.COLOR_GRAY2RGB)
    tp_pic = cv2.cvtColor(tp_edge, cv2.COLOR_GRAY2RGB)

    # 模板匹配
    res = cv2.matchTemplate(bg_pic, tp_pic, cv2.TM_CCOEFF_NORMED)
    _, _, _, max_loc = cv2.minMaxLoc(res)

    # 保存标注图
    vis = bg_img.copy()
    th, tw = tp_pic.shape[:2]
    cv2.rectangle(vis, max_loc, (max_loc[0] + tw, max_loc[1] + th), (0, 0, 255), 2)
    cv2.imwrite(out, vis)

    return {"x": int(max_loc[0])}


def download_image(url, filename):
    """下载图片"""
    response = requests.get(url,proxies=proxies)
    if response.status_code == 200:
        os.makedirs("images", exist_ok=True)
        filepath = os.path.join("images", filename)
        with open(filepath, "wb") as f:
            f.write(response.content)
        return filepath
    return None


def encrypt_AES(t: str, e: str) -> str:
    """
    AES加密
    :return:
    """
    js_file = """
        var CryptoJs = require("crypto-js")
        var U = CryptoJs.enc.Utf8.parse("0102030405060708")
            , encrypt = function(t, e) {
            e = CryptoJs.enc.Utf8.parse(e);
            var n = CryptoJs.enc.Utf8.parse(t);
            return CryptoJs.AES.encrypt(n, e, {
                iv: U
            }).toString()
        }
    """
    return execjs.compile(js_file).call("encrypt", t, e)


def MD5(d):
    """
    返回MD5加密
    :param d:
    :return:
    """
    return hashlib.md5(d.encode()).hexdigest()


def get_sign(data: str, key: str = "") -> str:
    """
    sign
    :return:
    """
    return encrypt_AES(MD5(data), key)


def checkSlidingVerifyCode(
    permanent_id,encryptKey: str, rankey: str, requestId: str, token: str, x, y
):
    """
    {
        x: t.left / 350,
        y: t.json.y
    }
    :return:
    """
    point_json = json.dumps(
        {"x": (int(x / (408 / 350))) / 350, "y": y}, separators=(",", ":")
    )
    point_json = encrypt_AES(point_json, encryptKey)
    slide_cost_time = str(random.randint(1500, 3000))
    url = "https://login.dangdang.com/api/customer/loginapi/checkSlidingVerifyCode"
    data = {
        "ct": "pc",
        "need_new_verifydata": "0",
        "permanent_id": permanent_id,
        "point_json": point_json,
        "requestId": requestId,
        "situation": "login",
        "slide_cost_time": slide_cost_time,
        "t": int(time.time() * 1000),
        "verifyToken": token,
    }
    sign = f"ct=pc&need_new_verifydata=0&permanent_id={permanent_id}&point_json={point_json}&requestId={requestId}&situation=login&slide_cost_time={slide_cost_time}&t={data.get('t')}&verifyToken={token}"
    data["sign"] = get_sign(sign, rankey)

    response = session.post(
        url,
        headers=headers,
        data=data,
        proxies={
            "http": "127.0.0.1:7890",
            "https": "127.0.0.1:7890",
        },
    )
    print(response.status_code)
    print(response.json())
    check_code = response.json().get("data", {}).get("checkCode")
    return check_code

def accountLogin(
    username: str,
    password: str,
    permanent_id: str,
    rankey: str,
    requestId: str,
    token: str,
    check_code: str,
):
    url = "https://login.dangdang.com/api/customer/loginapi/accountLogin"
    password = encrypt_AES(password, "qrcode_p@ssw0rdK")
    data = {
        "t": int(time.time() * 1000),
        "ct": "pc",
        "permanent_id": permanent_id,
        "requestId": requestId,
        "username": username,
        "password": password,
        "autokey": "off",
        "token": token,
        "check_code": check_code,
        "check_code_type": "1",
    }
    sign = f"autokey=off&check_code={check_code}&check_code_type=1&ct=pc&password={password}&permanent_id={permanent_id}&requestId={requestId}&t={data.get('t')}&token={token}&username={username}"
    data["sign"] = get_sign(sign, rankey)
    response = session.post(url, headers=headers, data=data,proxies=proxies)
    print(response.status_code)
    print(response.json())


if __name__ == "__main__":
    permanent_id=get_permanent_id()
    print("permanent_id==>", permanent_id)
    # 步骤 1: 获取 Rankey
    keydata = getRankey(permanent_id)
    requestId = keydata["requestId"]
    rankey = keydata["rankey"]

    # 步骤 2: 检查是否显示滑块
    isShowSlide(permanent_id, requestId, rankey)

    # 步骤 3: 获取滑块验证代码
    res = getSlidingVerifyCode(permanent_id,requestId, rankey)
    slideImg = res["slideImg"]
    y = res["y"]
    bgImg = res["bgImg"]
    heightRatio = res["heightRatio"]
    encryptKey = res["encryptKey"]
    token = res["token"]

    # 下载滑块和背景图
    slide_path = download_image(slideImg, f"slide_{int(time.time())}.png")
    bg_path = download_image(bgImg, f"bg_{int(time.time())}.jpg")

    # 步骤 4: 识别缺口位置
    print("\n📋 识别滑块位置")
    out_path = os.path.join("images", f"result_{int(time.time())}.jpg")
    gap_result = identify_gap(bg_path, slide_path, out_path)
    target_x = gap_result["x"]
    print(f"✅ 识别结果: x={target_x}")
    check_code = checkSlidingVerifyCode(
        permanent_id,encryptKey,rankey, requestId, token, target_x, y
    )
    print(f"✅ 验证结果: {check_code}")
    username: str = "13832321212"
    password: str = "123456"
    accountLogin(username, password, permanent_id=permanent_id,rankey=rankey, requestId=requestId, token=token, check_code=check_code)
